import BaseMod from "../core/mvc/BaseMod"
import App from "../App";
import { GameEvent } from "../../common/game/event/GameEvent";
import { Util } from "../../common/game/util/Util";
import Timer from "../../common/core/Timer";
import { Protocol } from "../../common/protocol/Protocol";
import { ClientEvent } from "../event/ClinetEvent";

const util = Util
const key_update_rank = "update_rank"
const get = GameEvent.Type
const cet = ClientEvent.Type


export interface ISnake {
    /** 蛇唯一标识 */
    id: number,
    /** 头部id */
    hid?: number,
    /** 蛇名称 */
    name: string,
}

export interface ISnakeNode {
    sid: number,
    /** 唯一标识 */
    id: number,
    x: number,
    y: number,
    w: number,
    ang: number,
    idx: number,
    color: string,
}

/** 蛇数据 */
export default class SnakeMod extends BaseMod {

    private static _ins: SnakeMod
    static get ins() { return SnakeMod._ins || (SnakeMod._ins = new SnakeMod()) }
    /** 蛇id映射 */
    private _snakeMap = new Map<number, ISnake>()
    /** 节点id映射 */
    private _nodeMap = new Map<number, ISnakeNode>()


    /** 排行榜 */
    private _rankArr: { id: number, score: number }[] = []

    /** 可见蛇节点集合 */
    private _screenNodeSet: Set<number>

    /** 计时器 */
    private _timer = new Timer()

    protected initLocal(): void {
        this._timer.set(key_update_rank, 1000, Date.now())
        this._screenNodeSet = new Set()
        let { loadSnakes } = App.localPlayer.updateLoadedSnakeMap(new Set())
        loadSnakes.forEach(snake => {
            this._snakeMap.set(snake.id, snake)
        })

        //蛇增加
        this.gd.on(get.SNAKE_ADD, this, e => {
            let { snake } = e
            this._snakeMap.set(snake.id, snake)
        })
        //蛇移除
        this.gd.on(get.SNAKE_REMOVE, this, e => {
            this._snakeMap.delete(e.snake.id)
        })

        //排行榜更新
        this.gd.on(get.RANK_UPDATE, this, e => {
            this._rankArr = []
            //取前十
            e.rankArr.slice(0, 10).forEach(snake => {
                this._rankArr.push({
                    id: snake.id,
                    score: snake.score
                })
            })
            this.ed.send(cet.RANK_UPDATE, { rankArr: this._rankArr })
        })

        //游戏帧更新
        this.gd.on(get.GAME_UPDATE, this, () => {
            let player = App.localPlayer

            //更新可见蛇节点，获取待加载的和待卸载的蛇节点
            let { loadNodeMap, unloadNodeIdSet } = player.updateScreenNodeMap(this._screenNodeSet)

            let loadNodes: ISnakeNode[] = []
            let unloadNodeIds = Array.from(unloadNodeIdSet)
            unloadNodeIds.forEach(nodeId => this._nodeMap.delete(nodeId))

            loadNodeMap.forEach((nodes, snake) => {
                let colors = snake.colors
                nodes.forEach(node => {
                    let snakeNode: ISnakeNode = {
                        sid: snake.id,
                        id: node.id,
                        x: node.x,
                        y: node.y,
                        w: node.w,
                        ang: node.ang - 90,
                        color: colors[node.idx % colors.length],
                        idx: node.idx
                    }
                    loadNodes.push(snakeNode)
                    this._nodeMap.set(snakeNode.id, snakeNode)
                })
            })

            //发送事件通知view更新
            loadNodes.length && this.ed.send(cet.NODE_LOAD, { loadNodes })
            unloadNodeIds.length && this.ed.send(cet.NODE_UNLOAD, { unloadNodeIds })

            //更新排行榜
            this._timer.check(key_update_rank, () => {
                App.localGame.world.updateRank()
            })
        })
    }

    protected initRemote(): void {

        //蛇增加
        this.pd.on(Protocol.S2C_SNAKE_LOAD, this, data => {
            let { loadSnakes } = data
            loadSnakes.forEach(snake => {
                this._snakeMap.set(snake.id, snake)
            })
        })
        //蛇移除
        this.pd.on(Protocol.S2C_SNAKE_UNLOAD, this, data => {
            let { unloadSnakeIds } = data
            unloadSnakeIds.forEach(snakeId => {
                this._snakeMap.delete(snakeId)
            })
        })

        //蛇节点加载
        this.pd.on(Protocol.S2C_SNAKE_NODE_LOAD, this, data => {

            let { loadSnakes } = data
            let loadNodes: ISnakeNode[] = []
            loadSnakes.forEach(snake => {
                let colors: string[] = []
                snake.rgbs.forEach(rgb => {
                    colors.push(util.rgb2color(rgb))
                })
                snake.loadNodes.forEach(node => {
                    let snakeNode: ISnakeNode = {
                        sid: snake.id,
                        id: node.id,
                        x: node.x / 100,
                        y: node.y / 100,
                        w: snake.w / 100,
                        ang: node.ang / 100 - 90,
                        color: colors[node.idx % colors.length],
                        idx: node.idx
                    }
                    loadNodes.push(snakeNode)
                    this._nodeMap.set(snakeNode.id, snakeNode)
                })
            })

            //发送事件通知view更新
            loadNodes.length && this.ed.send(cet.NODE_LOAD, { loadNodes })
        })

        //蛇节点卸载
        this.pd.on(Protocol.S2C_SNAKE_NODE_UNLOAD, this, data => {
            let { unloadNodeIds } = data
            //发送事件通知view更新
            unloadNodeIds.length && this.ed.send(cet.NODE_UNLOAD, { unloadNodeIds })
        })

        this.pd.on(Protocol.S2C_SNAKE_HID_UPDATE, this, data => {
            let { snakes } = data
            snakes.forEach(snake => {
                let _snake = this._snakeMap.get(snake.id)
                if (_snake) {
                    _snake.hid = snake.hid
                }
            })
        })
    }

    getSnake(id: number) {
        return this._snakeMap.get(id)
    }

    getSnakeNode(id: number) {
        return this._nodeMap.get(id)
    }

}